
"""
J,M,S,X,W,P,B 分别代码车， 马， 士， 相， 将， 炮， 兵
开局的棋子：

J1, J2, M1, M2, S1, S2, X1, X2, W, P1, P2, B1, B2, B3, B4, B4

R 代表红方
B 代表黑方
J1 在1路
J2 在9路
右手边是1路， 左手边是9路
红方的1路是黑方的9路
位置描述， P1 的起始位置是 (2,3) 2路3线， 第一步， 炮2平5， 架当头炮。
第一步红方， 走棋描述为 ("RP1", (2, 3), (5, 3)), 2路炮移到5路
下一步棋，黑方走棋描述为 ("BP1", (2, 3), (5, 3)), 2路炮移到5路, 但这里的2路是黑方的8路。
"""
import os

# 定义颜色的ANSI Escape序列
import time
from copy import deepcopy

from app import tools

COLOR_RED = '\033[91m'
COLOR_GREEN = '\033[92m'
COLOR_YELLOW = '\033[93m'
COLOR_BLUE = '\033[94m'
COLOR_CYAN = '\033[96m'
COLOR_PURPLE = '\033[95m'
COLOR_GRAY = '\033[90m'
COLOR_RESET = '\033[0m'


class ChessGame(object):
    """
    piece_weight 各个棋子的权重
    """
    player_option = ("B", "R")
    piece_name = ('M1', 'M2', 'P1', 'P2', 'J1', 'J2', 'B1', 'B2', 'B3', 'B4', 'B5', 'S1', 'S2', 'X1', 'X2', 'W')
    ROW_NUM = 10
    COL_NUM = 9
    player_reverse_map = {
        'B': 'R',
        'R': 'B'
    }
    piece_weight = {
        "W": 10,
        "S": 3,
        "X": 2,
        "B": 1,
        "P": 4,
        "M": 5,
        "J": 8
    }

    def __init__(self, data=None):
        if data is None:
            self.__status = [
                ["RJ1", "RM1", "RX1", "RS1", "RW", "RS2", "RX2", "RM2", "RJ2"],
                ["", "",  "",    "",    "",   "",    "",    "",    ""],
                ["",    "RP1", "",    "",    "",   "",    "",    "RP2", ""],
                ["RB1", "",    "RB2", "",    "RB3", "",   "RB4", "",    "RB5"],
                ["", "", "", "", "", "", "", "", ""],
                ["", "", "", "", "", "", "", "", ""],
                ["BB5", "", "BB4", "", "BB3", "", "BB2", "", "BB1"],
                ["", "BP2", "", "", "", "", "", "BP1", ""],
                ["", "", "", "", "", "", "", "", ""],
                ["BJ2", "BM2", "BX2", "BS2", "BW", "BS1", "BX1", "BM1", "BJ1"],
            ]
            self.__cur = "R"   # 定义那一方先走棋， 红方先走。
            self.__count = 0
            # self.__dead_game = False
            self.__dead_piece = []
        else:
            self.__status = deepcopy(data.get('status'))
            self.__cur = data.get('player')
            self.__count = data.get('count')
            self.__dead_piece = deepcopy(data.get('dead_piece'))

        self.__piece_index = {}
        self.build_piece_index()

        self.__player_attack = {
            'B': {},
            'R': {}
        }
        self.__player_attack_reverse = {
            'B': {},
            'R': {}
        }
        # self.build_piece_attack('B')
        # self.build_piece_attack('R')

    # @property
    # def dead_game(self):
    #     return self.__dead_game
    #
    # @dead_game.setter
    # def dead_game(self, flag):
    #     self.__dead_game = flag

    def get_status_piece(self, index):
        """根据数据索引获取棋子信息。
        :param index: 索引, 例如，[0,4]
        """
        i, j = index[:]
        return self.__status[i][j]

    def build_piece_index(self):
        """构建当前棋盘棋子的索引。
        """
        self.__piece_index = {}
        for i, row in enumerate(self.__status):
            for j, p in enumerate(row):
                if p:
                    self.__piece_index[p] = (i, j)

    def get_piece_index(self, piece):
        """查找棋子的位置。
        :param piece: 棋子

        :return 返回位置， 例如， [2,5]
        """
        if not piece:
            return
        # self.build_piece_index()
        return self.__piece_index.get(piece)

    def _check_index_range(self, x):
        """检查坐标参数的合法范围。"""
        return 0 <= x[0] < self.ROW_NUM and 0 <= x[1] < self.COL_NUM

    def _cal_m_move_opt(self, index):
        """棋子马的粗略的走棋位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i-2, j-1), (i-2, j+1), (i+2, j-1), (i+2, j+1),
                    (i-1, j-2), (i-1, j+2), (i+1, j-2), (i+1, j+2))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('m move_opt:', move_opt)
        return move_opt

    def _cal_b_move_opt(self, index):
        """棋子兵粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i, j-1), (i, j+1), (i-1, j), (i+1, j))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('b move_opt:', move_opt)
        return move_opt

    def _cal_x_move_opt(self, index):
        """棋子象粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i+2, j+2), (i+2, j-2), (i-2, j+2), (i-2, j-2))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('x move_opt:', move_opt)
        return move_opt

    def _cal_s_move_opt(self, index):
        """棋子士粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = ((i+1, j+1), (i+1, j-1), (i-1, j+1), (i-1, j-1))
        move_opt = list(filter(lambda x: self._check_index_range(x), move_opt))
        print('m move_opt:', move_opt)
        return move_opt

    def _cal_p_j_move_opt(self, index):
        """棋子炮，车粗略的走棋的位置。"""
        print = tools.dump_func
        i, j = index[:]
        move_opt = []
        for x in range(self.ROW_NUM):
            if x == i:
                continue
            move_opt.append((x, j))
        for x in range(self.COL_NUM):
            if x == j:
                continue
            move_opt.append((i, x))
        #
        print('p j move_opt:', move_opt)
        return move_opt

    def __xx_build_piece_attack(self, player):
        """Todo: 这个函数后面要重构， 把计算所有可能走法的代码抽出来，其他函数可以复用
        这个函数可以废弃了。
        """
        print = tools.dump_func
        print("\n======= start build_piece_attack")
        reverse_player = self.player_reverse_map.get(player)
        self.__player_attack[player] = {}
        self.__player_attack_reverse[reverse_player] = {}
        # 先建立所有棋子的位置信息，不用重复计算。
        self.build_piece_index()
        attack_piece_list = list(map(lambda x: player + x, self.piece_name))
        for piece in attack_piece_list:
            piece_index = self.get_piece_index(piece)
            print('build_piece_attack:', piece, piece_index)
            if not piece_index:
                continue
            move_opt = []
            check_rule = None

            if 'M' == piece[1]:
                move_opt = self._cal_m_move_opt(piece_index)
                check_rule = self.piece_m_rule
            elif 'P' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_p_rule
            elif 'J' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_j_rule
            elif 'B' == piece[1]:
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_b_rule
            elif 'X' == piece[1]:
                move_opt = self._cal_x_move_opt(piece_index)
                check_rule = self.piece_x_rule
            elif 'S' == piece[1]:
                move_opt = self._cal_s_move_opt(piece_index)
                check_rule = self.piece_s_rule
            elif 'W' == piece[1]:
                # 将的走棋规则跟兵相似， 这里借用兵的大致走棋规则
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_w_rule

            for index in move_opt:
                # opt_pos = self.get_bord_pos(player, index)
                # print()
                opt_piece = self.get_status_piece(index)
                print('  opt_piece:', opt_piece, index)
                if not opt_piece or opt_piece[0] == player:
                    continue
                cur_pos = self.get_bord_pos(player, piece_index)
                target_pos = self.get_bord_pos(player, index)
                rv = check_rule((piece, cur_pos, target_pos))
                print('opt_piece:', index, opt_piece, rv)
                if 'OK' != rv:
                    continue

                if not self.__player_attack[player].get(piece):
                    self.__player_attack[player][piece] = []
                self.__player_attack[player][piece].append(opt_piece)
        #
        for k, v in self.__player_attack[player].items():
            for p in v:
                if not self.__player_attack_reverse[reverse_player].get(p):
                    self.__player_attack_reverse[reverse_player][p] = []
                self.__player_attack_reverse[reverse_player][p].append(k)

        print('__player_attack B:', self.__player_attack['B'])
        print('__player_attack R:', self.__player_attack['R'])

        print('__player_attack_reverse R:', self.__player_attack_reverse['R'])
        print('__player_attack_reverse B:', self.__player_attack_reverse['B'])

    def get_piece_attack(self):
        """根据双方所有可以走棋的选择， 计算双方可以攻击的棋子以及可以被攻击的棋子。
        计算局面得分信息规则：
        W - 10
        S - 3
        X - 2
        B - 1
        P - 4
        M - 5
        J - 8
        """
        cur_player = self.__cur
        opponent_player = self.player_reverse_map.get(cur_player)
        opt_move = self.get_player_opt_move(cur_player)
        opponent_opt_move = self.get_player_opt_move(opponent_player)
        attack_info = {
            'R': {},
            'B': {}
        }
        attack_info_backward = {
            'R': {},
            'B': {}
        }

        def update_attack_info(player, opt_move_data):
            player_reverse = self.player_reverse_map.get(player)
            player_attack_info = attack_info[player]
            player_attack_info_backward = attack_info_backward[player_reverse]

            for item in opt_move_data:
                move, target_piece = item[:]
                piece = move[0]

                if not self.piece_empty(target_piece):
                    if piece not in player_attack_info:
                        player_attack_info[piece] = []
                    player_attack_info[piece].append(target_piece)
                    #
                    if target_piece not in player_attack_info_backward:
                        player_attack_info_backward[target_piece] = []
                    player_attack_info_backward[target_piece].append(piece)

        update_attack_info(cur_player, opt_move)
        update_attack_info(opponent_player, opponent_opt_move)
        # 更新局面得分信息。
        attack_score = {
            "R": 0,
            "B": 0
        }
        attack_score_backward = {
            "R": 0,
            "B": 0
        }

        for player, info in attack_info.items():
            score = 0
            for p, v in info.items():
                score += sum([self.piece_weight.get(x[1]) for x in v])
            attack_score[player] = score

        for player, info in attack_info_backward.items():
            score = 0
            for p, v in info.items():
                score += self.piece_weight.get(p[1]) * len(v)
            attack_score_backward[player] = -score
        # 计算得分的差值
        # print()
        score_diff = {
            "R": attack_score["R"] + 2*attack_score_backward["R"],
            "B": attack_score["B"] + 2*attack_score_backward["B"],
        }

        return {
            'attack_info': attack_info,
            'attack_info_backward': attack_info_backward,
            'opt_move': opt_move,
            'attack_score': attack_score,
            'attack_score_backward': attack_score_backward,
            "score_diff": score_diff
        }

    def get_player_opt_move(self, player):
        """获取玩家所有的可能走法"""
        print = tools.dump_func
        opt_move = []
        self.build_piece_index()
        attack_piece_list = list(map(lambda x: player + x, self.piece_name))
        for piece in attack_piece_list:
            piece_index = self.get_piece_index(piece)
            print('build_piece_attack:', piece, piece_index)
            if not piece_index:
                continue
            move_opt = []
            check_rule = None

            if 'M' == piece[1]:
                move_opt = self._cal_m_move_opt(piece_index)
                check_rule = self.piece_m_rule
            elif 'P' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_p_rule
            elif 'J' == piece[1]:
                move_opt = self._cal_p_j_move_opt(piece_index)
                check_rule = self.piece_j_rule
            elif 'B' == piece[1]:
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_b_rule
            elif 'X' == piece[1]:
                move_opt = self._cal_x_move_opt(piece_index)
                check_rule = self.piece_x_rule
            elif 'S' == piece[1]:
                move_opt = self._cal_s_move_opt(piece_index)
                check_rule = self.piece_s_rule
            elif 'W' == piece[1]:
                # 将的走棋规则跟兵相似， 这里借用兵的大致走棋规则
                move_opt = self._cal_b_move_opt(piece_index)
                check_rule = self.piece_w_rule

            for index in move_opt:
                # opt_pos = self.get_bord_pos(player, index)
                # print()
                opt_piece = self.get_status_piece(index)
                print('  opt_piece:', opt_piece, index)
                if not self.piece_empty(opt_piece) and opt_piece[0] == player:
                    continue
                cur_pos = self.get_bord_pos(player, piece_index)
                target_pos = self.get_bord_pos(player, index)
                rv = check_rule((piece, cur_pos, target_pos))
                print('opt_piece:', index, opt_piece, rv)
                if 'OK' != rv:
                    continue
                opt_move.append([[piece, cur_pos, target_pos], opt_piece])
        return opt_move

    def print_status(self):
        print("       ", end='')
        for c in range(len(self.__status[0])):
            print(f" {c+1}  ", end='')
        print("")
        for r, row in enumerate(self.__status):
            print(f"{r+1:<2}-{(9-r)+1:>2}| ", end="")
            for c, col in enumerate(row):
                col = col.strip()
                if not col:
                    col = '--'
                    print(f"{col:<4}", end='')
                elif "R" == col[0]:
                    print(COLOR_RED+f"{col:<4}"+COLOR_RESET, end='')
                else:
                    print(f"{col:<4}", end='')
            print("")

        print("       ", end='')
        for c in range(len(self.__status[0]), 0, -1):
            print(f" {c}  ", end='')
        print("")

    def get_status_pos(self, player, desc):
        """根据棋谱坐标计算内部数据索引"""
        if player not in self.player_option:
            return "Error.WrongParam"
        if "B" == player:
            return 10 - desc[1], 9 - desc[0]
        elif "R" == player:
            return desc[1] - 1, desc[0] - 1

    def get_bord_pos(self, player, desc):
        """根据内部数据索引计算棋谱坐标"""
        if player not in self.player_option:
            return "Error.WrongParam"
        if "B" == player:
            return 9 - desc[1], 10 - desc[0]
        elif "R" == player:
            return desc[1] + 1, desc[0] + 1

    def get_bord_status(self):
        return {
            'status': self.__status,
            'player': self.__cur,
            'count': self.__count,
            # 'dead_game': self.__dead_game,
            # 'player_attack_reverse': self.__player_attack_reverse,
            # 'last_dead_piece': self.__dead_piece[-1:]
            'dead_piece': self.__dead_piece
        }

    def rewind_step(self, player, piece_move, target_piece):
        from_piece = piece_move[0]
        status_pos_from = self.get_status_pos(player, piece_move[1])
        status_pos_to = self.get_status_pos(player, piece_move[2])
        # last_dead_piece = self.__dead_piece[-1:]
        x1, y1 = status_pos_from[:]
        x2, y2 = status_pos_to[:]
        self.__status[x1][y1] = from_piece
        if not self.piece_empty(target_piece):
            self.__status[x2][y2] = target_piece
            self.__dead_piece.pop()
        self.__count -= 1

    def check_kill_game(self):
        """扫描所有可能的走棋"""
        cur_player = self.__cur
        opponent_player = self.player_reverse_map.get(cur_player)
        # 检查所有的可能的解法。
        print('start find opt move ...')
        opt_move = self.get_player_opt_move(cur_player)
        print('finish find opt move ...')
        attack_info = []
        all_result = []
        for move_desc in opt_move:
            # print("move_desc:", move_desc)
            target_piece = self.change_status_raw(move_desc[0])
            # 走了一步之后， 扫描对方所有可能的走法
            opponent_opt_move = self.get_player_opt_move(opponent_player)
            result = map(lambda x: True if x[1] and x[1][1] == 'W' else False, opponent_opt_move)

            # for opponent_move_desc in opponent_opt_move:
            #     print("    opponent_move_desc:", opponent_move_desc)
            # print('  opponent result:', list(result))
            all_result.append(any(result))
            self.rewind_status_raw(*move_desc)
            # self.print_status()

        # 每一种走棋， 对方都可以将军。表示死棋。
        if all(all_result):
            return True
        else:
            return False

    @classmethod
    def check_pos_valid(cls, desc):
        if 1 <= desc[0] <= 9 and 1 <= desc[1] <= 10:
            return True
        return False

    @classmethod
    def piece_empty(cls, piece):
        return not piece.strip()

    def have_piece(self, player, target_pos):
        """判断这个是否有棋子"""
        pieces = self.get_pos_piece(player, target_pos)
        if not self.piece_empty(pieces):
            return True
        return False

    def get_pos_piece(self, player, pos):
        x, y = self.get_status_pos(player, pos)
        return self.__status[x][y]

    def check_w_same_road(self):
        player = self.__cur
        rw_pos = self.get_piece_pos(player, 'RW')
        bw_pos = self.get_piece_pos(player, 'BW')
        if rw_pos and bw_pos and rw_pos[0] == bw_pos[0]:
            piece_num = self.get_road_piece_num(player, rw_pos[0], rw_pos[1], bw_pos[1])
            if 0 == piece_num:
                return True
        return False

    @property
    def cur_player(self):
        """获取当前的执棋方。 """
        return self.__cur

    @property
    def opponent_player(self):
        """获取对方的玩家。 """
        return self.player_reverse_map.get(self.__cur)

    def change_status_raw(self, move):
        """这个函数只是单纯的改变状态， 大部分情况下， 改变状态后， 还需要检查其他规则，如果不符合规则，需要回退状态。
        返回值是目标位置的棋子。"""
        #
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        #
        x, y = self.get_status_pos(player, cur_pos)[:]
        self.__status[x][y] = ""
        x2, y2 = self.get_status_pos(player, target_pos)[:]
        target_piece = self.__status[x2][y2]
        if not self.piece_empty(target_piece):
            self.__dead_piece.append(target_piece)
        self.__status[x2][y2] = piece
        return target_piece

    def rewind_status_raw(self, move, target_piece):
        """这个函数是回退的操作.
        @param move  上一步操作的数据。
        @param target_piece 是上一步操作目标位置的棋子。"""
        #
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        #
        x1, y1 = self.get_status_pos(player, cur_pos)[:]
        x2, y2 = self.get_status_pos(player, target_pos)[:]

        self.__status[x1][y1] = piece
        if not self.piece_empty(target_piece):
            self.__status[x2][y2] = target_piece
            dead_piece = self.__dead_piece.pop()
            assert dead_piece == target_piece
        else:
            self.__status[x2][y2] = ""

    def piece_p_rule(self, move):
        """炮的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        # 炮也只能走直线。
        if road != road2 and line != line2:
            return "Error.WrongMove"
        # 前进或后退
        elif road == road2:
            piece_num = self.get_road_piece_num(player, road, line, line2)
        # 平移
        elif line == line2:
            # 有两种情况， 一种是路线是空的
            piece_num = self.get_line_piece_num(player, line, road, road2)
        else:
            return "Error.WrongMove"
        #
        target_piece = self.get_pos_piece(player, target_pos)
        if piece_num > 1:
            return "Error.WrongMove"
        if piece_num == 0 and not self.piece_empty(target_piece):
            return "Error.WrongMove"
        if piece_num == 1 and self.piece_empty(target_piece):
            return "Error.WrongMove"
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove"
        # return self.change_status(move)
        # return "OK"
        return "OK"

    def piece_same_player(self, player, target_pos):
        """判断目标位置是否是己方棋子"""
        target_piece = self.get_pos_piece(player, target_pos)
        # print('piece_same_player:', target_pos, player, target_piece)
        #
        if not self.piece_empty(target_piece):
            target_player = target_piece[0]
            if target_player == player:
                return True
        return False

    def piece_m_rule(self, move):
        """马的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if abs(road - road2) == 1 and abs(line - line2) == 2:
            if line2 > line:   # 进马
                m_leg_pos = (road, line + 1)  # 马腿位置
                m_leg_piece = self.get_pos_piece(player, m_leg_pos)
            else:
                m_leg_pos = (road, line - 1)  # 马腿位置
                m_leg_piece = self.get_pos_piece(player, m_leg_pos)

            if not self.piece_empty(m_leg_piece):
                return "Error.WrongMove"
            target_piece = self.get_pos_piece(player, target_pos)
            #
            if not self.piece_empty(target_piece):
                target_player = target_piece[0]
                if target_player == player:
                    return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"

        elif abs(road - road2) == 2 and abs(line - line2) == 1:
            if road > road2:  #
                m_leg_pos = (road - 1, line)  # 马腿位置
            else:
                m_leg_pos = (road + 1, line)  # 马腿位置
            #
            # print("m_leg_pos:", m_leg_pos)
            if self.have_piece(player, m_leg_pos):
                return "Error.WrongMove.Barrier"
            if self.piece_same_player(player, target_pos):
                return "Error.WrongMove"
            #
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

        # return "OK"

    def piece_b_rule(self, move):
        """兵的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if road == road2:  # 进兵
            if line2 == line + 1:
                if not self.piece_same_player(player, target_pos):
                    # return self.change_status(move)
                    return "OK"
                else:
                    return "Error.WrongMove"
            else:
                return "Error.WrongMove"
        elif line == line2 and line > 5:  # 兵平移, 过河兵才可以平移
            if not (abs(road - road2) == 1):
                return "Error.WrongMove"
            # elif self.piece_same_player(player, target_pos):
            #     return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"
        #
        # return "OK"

    def empty_road(self, player, road, line, line2):
        start = min(line, line2)
        end = max(line, line2)
        empty_flag = True
        for i in range(start+1, end, 1):
            temp_piece = self.get_pos_piece(player, (road, i))
            if not self.piece_empty(temp_piece):
                empty_flag = False
                break
        return empty_flag

    def get_road_piece_num(self, player, road, line, line2):
        """计算某一路上棋子的个数。 """
        start = min(line, line2)
        end = max(line, line2)
        piece_num = 0
        for i in range(start + 1, end, 1):
            temp_piece = self.get_pos_piece(player, (road, i))
            if not self.piece_empty(temp_piece):
                piece_num += 1
        return piece_num

    def get_line_piece_num(self, player, line, road, road2):
        """计算某一线上棋子的个数。 """
        start = min(road, road2)
        end = max(road, road2)
        piece_num = 0
        for i in range(start + 1, end, 1):
            temp_piece = self.get_pos_piece(player, (i, line))
            if not self.piece_empty(temp_piece):
                piece_num += 1
        return piece_num

    def empty_line(self, player, line, road, road2):
        print = tools.dump_func
        print("empty_line:", line, road, road2)
        start = min(road, road2)
        end = max(road, road2)
        print("start:", start, end)
        empty_flag = True
        for i in range(start+1, end, 1):
            print("road:", i)
            temp_piece = self.get_pos_piece(player, (i, line))
            if not self.piece_empty(temp_piece):
                empty_flag = False
                break
        return empty_flag

    def piece_j_rule(self, move):
        """车的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        # print("piece_j_rule:", move)

        # 这个是通用判断， 可以放到外层去。
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove"
        #
        if road == road2:  # 前进或后退
            # print("j_rule:", player, road, line, line2)
            if not self.empty_road(player, road, line, line2):
                return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        elif line == line2:  # 平移
            if not self.empty_line(player, line, road, road2):
                return "Error.WrongMove.Barrier"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"
        # return "OK"

    def piece_x_rule(self, move):
        """象的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 5:   # 象不能过河
            return "Error.WrongMove"
        # print("piece_j_rule")
        if abs(road - road2) == 2 and abs(line - line2) == 2:
            # 象眼的位置
            x_eye_pos = ((road + road2) // 2, (line + line2) // 2)
            if self.have_piece(player, x_eye_pos):
                return "Error.WrongMove.Barrier"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

    def piece_s_rule(self, move):
        """士的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 3 or road2 < 4 or road2 > 6:   # 士只能在九宫格内活动
            return "Error.WrongMove"
        # print('piece_s_rule:', abs(road - road2), abs(line - line2))
        if (abs(road - road2) == 1) and (abs(line - line2) == 1):
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

        # return "OK"

    def get_piece_pos(self, player, piece):
        """status_index 表示内部二维列表的索引坐标， board_pos 一般表示棋盘坐标，是跟执棋方相关的。 """
        status_index = self.get_piece_index(piece)
        return self.get_bord_pos(player, status_index)
        # for i, r in enumerate(self.__status):
        #     for j, p in enumerate(r):
        #         if p == piece:
        #             # print('get_piece_pos:', (i, j))
        #             return self.get_bord_pos(player, (i, j))

    def piece_w_rule(self, move):
        """老蒋的走棋规则"""
        piece, cur_pos, target_pos = move[:]
        player = piece[0]
        road, line = cur_pos[:]
        road2, line2 = target_pos[:]
        if line2 > 3 or road2 < 4 or road2 > 6:   # 老蒋只能在九宫格内活动
            return "Error.WrongMove"
        # print('piece_s_rule:', abs(road - road2), abs(line - line2))
        if ((road == road2) and (abs(line - line2) == 1)) or ((line == line2) and (abs(road - road2) == 1)):
            # w_pos = None
            # if 'B' == player:
            #     w_pos = self.get_piece_pos(player, 'RW')
            # elif 'R' == player:
            #     w_pos = self.get_piece_pos(player, 'BW')
            # #
            # if not w_pos:
            #     return "Error.ProcWrong"
            # print('w_pos:', w_pos)
            # if w_pos[0] == road2:
            #     return "Error.WrongMove"
            # return self.change_status(move)
            return "OK"
        else:
            return "Error.WrongMove"

    def switch_player(self):
        if "B" == self.__cur:
            self.__cur = "R"
        elif "R" == self.__cur:
            self.__cur = "B"
        self.__count += 1

    def step_check(self, move):
        """象棋走一步棋的处理。
        :param move:  走棋的描述。 格式为（棋子，当前位置， 目标位置）
        """
        piece, cur_pos, target_pos = move[:]
        # 走棋位置的检查，要在棋盘范围内。
        if not self.check_pos_valid(cur_pos) or not self.check_pos_valid(target_pos):
            return "Error.WrongData.InvalidPos"

        # 目标位置是同一方的棋子是无效数据
        player = piece[0]
        if self.piece_same_player(player, target_pos):
            return "Error.WrongMove.SamePlayerPiece"
        # 位置没有变化是无效数据, 判断走棋规则用象棋术语坐标。
        # 判断棋盘的状态用， 内部的数组索引。
        if cur_pos == target_pos:
            return "Error.WrongData.SamePos"
        # 走棋是否是当前下棋方。
        if player != self.__cur:
            return "Error.WrongData.WrongPlayer"
        # 棋子正确性的检查
        cur_piece = self.get_pos_piece(player, cur_pos)
        if piece != cur_piece:
            return "Error.WrongData.PieceWrong"
        #
        # 移动的目标位置。
        piece_type = piece[1]

        # 棋子是车
        res = "Error"
        #  棋子是炮
        if "P" == piece_type:
            res = self.piece_p_rule(move)
        elif "M" == piece_type:
            res = self.piece_m_rule(move)
        elif "B" == piece_type:
            res = self.piece_b_rule(move)
        elif "J" == piece_type:
            res = self.piece_j_rule(move)
        elif "X" == piece_type:
            res = self.piece_x_rule(move)
        elif "S" == piece_type:
            res = self.piece_s_rule(move)
        elif 'W' == piece_type:
            res = self.piece_w_rule(move)

        # 把下面这些逻辑移出这个函数。
        # if "OK" == res:
        #     res = self.change_status(move)
        #     if 'OK' != res:
        #         return res
        #
        # self.build_piece_index()
        # # self.build_piece_attack('B')
        # # self.build_piece_attack('R')
        #
        # # self.scan_attack()
        # self.switch_player()

        return res


def main():
    game = ChessGame()
    game.print_status()
    move_set = (
        ("BP1", (2, 3), (5, 3)),
        ("RP1", (2, 3), (5, 3)),
        ("BM1", (2, 1), (3, 3)),
        ("RB4", (7, 4), (7, 5)),
        ("BJ1", (1, 1), (2, 1)),
        ("RM2", (8, 1), (7, 3)),
        ("BJ1", (2, 1), (2, 5)),
        ("RM1", (2, 1), (3, 3)),
        ("BB2", (3, 4), (3, 5)),
        ("RJ1", (1, 1), (2, 1)),
        ("BP2", (8, 3), (7, 3)),
        ("RJ1", (2, 1), (2, 7)),
        ("BB4", (7, 4), (7, 5)),
        ("RJ1", (2, 7), (3, 7)),
        ("BB2", (3, 5), (3, 6)),
        ("RB2", (3, 4), (3, 5)),
        ("BB4", (7, 5), (7, 6)),
        ("RJ1", (3, 7), (3, 5)),
        ("BB2", (3, 6), (3, 7)),
        ("RM2", (7, 3), (5, 2)),
        ("BJ1", (2, 5), (6, 5)),
        ("RM1", (3, 3), (4, 5)),
        ("BP1", (5, 3), (5, 7)),
        ("RP2", (8, 3), (9, 3)),
        ("BX2", (7, 1), (5, 3)),
        ("RM1", (4, 5), (3, 3)),
        ("BB2", (3, 7), (4, 7)),
        # ("RJ2", (9, 1), (8, 1)),
        # ("BM1", (3, 3), (4, 5)),
        # ("RJ1", (3, 5), (6, 5)),
        # ("BB2", (4, 7), (3, 7)),
        # ("RJ2", (8, 1), (8, 4)),
        # ("BB2", (4, 7), (3, 7)),
        # ("RJ1", (3, 5), (3, 4)),
        ("RM1", (3, 3), (5, 4)),
        ("BB2", (4, 7), (5, 7)),
        ("RP1", (5, 3), (3, 3)),
        ("BP2", (7, 3), (7, 8)),
        ("RJ1", (3, 5), (3, 3)),

    )
    print("\033c", end="")
    game.print_status()
    # time.sleep(1)

    for i, move in enumerate(move_set):
        # os.system("clear")
        print("\033c", end="")
        if i == len(move_set) - 1:
            print("debug stop!")
        res = game.step(move)    # 炮2平5
        print("res:", res)
        if "OK" == res:
            print("\n==================== step:", i + 1)
            game.print_status()
        # time.sleep(1.5)


def test_print_with_color():
    # 定义颜色的ANSI Escape序列
    # COLOR_RED = '\033[91m'
    # COLOR_GREEN = '\033[92m'
    # COLOR_YELLOW = '\033[93m'
    # COLOR_BLUE = '\033[94m'
    # COLOR_CYAN = '\033[96m'
    # COLOR_PURPLE = '\033[95m'
    # COLOR_GRAY = '\033[90m'
    # COLOR_RESET = '\033[0m'

    # 打印带有颜色的文本
    print(COLOR_RED + "红色文本" + COLOR_RESET)
    print(COLOR_GREEN + "绿色文本" + COLOR_RESET)
    print(COLOR_YELLOW + "黄色文本" + COLOR_RESET)


def test_build_attack_piece():
    game = ChessGame()


if __name__ == "__main__":
    # main()
    # test_print_with_color()
    test_build_attack_piece()

